package constants.session;

import play.Play;
import play.cache.Cache;
import play.libs.Codec;
import play.mvc.Http;

import java.util.regex.Pattern;


/**
 * Author: yangzhi@djcars.cn
 * Create: 2012-05-31 14:01
 */
public class Session {

    static ThreadLocal<Session> current = new ThreadLocal<Session>();

    /**
     * Session ID的存储键值
     */
    final static String SESSION_ID_KEY = Play.configuration.getProperty("session.key", "__SESSIONID");
    /**
     * UUID ID的存储键值
     */
    final static String UUID_ID_KEY = Play.configuration.getProperty("uuid.key", "__UUID");
    /**
     * Session数据的存储前缀
     */
    private final static String SESSION_DAT_PREFIX = Play.configuration.getProperty("session.prefix", "SESSION");
    /**
     * Session数据的默认过期时间。Ex: 10s, 3mn, 8h
     */
    private final static String SESSION_DAT_EXPIRE = Play.configuration.getProperty("session.maxAge", "30mn");
    static Pattern sessionParser = Pattern.compile("^[0-9A-Fa-f]{32}$");
    static Pattern uuidParser = Pattern.compile("^[\\s]{36}$");

    Session() {

    }

    /**
     * @param sessionId
     */
    private Session(String sessionId) {
        this.sessionId = sessionId;
    }

    /**
     * 返回当前会话的Session
     */
    public static Session current() {
        return current.get();
    }

    /**
     * 根据sessionId构造对象
     *
     * @param sessionId
     */
    public static Session fromSessionId(String sessionId) {
        return new Session(sessionId);
    }

    /**
     * 当前的会话是否是新建的
     */
    private boolean isNew = false;

    /**
     * 当前的会话是否是新建的
     */
    public boolean isNewSession() {
        return this.isNew;
    }

    /**
     * 当前的会话是否是由cookie模式获取的
     */
    private boolean isCookieless = false;

    /**
     * 当前的会话是否是由cookie模式获取的
     */
    public boolean isCookieless() {
        return isCookieless;
    }

    /**
     * 会话id
     */
    private String sessionId = null;

    /**
     * 用户标示
     */
    private String uuid = null;


    /**
     * 当前的会话是否是新建的
     */
    private boolean isUuidNew = false;

    /**
     * 当前的会话是否是新建的
     */
    public boolean isUuidNewSession() {
        return this.isUuidNew;
    }

    /**
     * 当前的会话是否是由cookie模式获取的
     */
    private boolean isUuidCookieless = false;

    /**
     * 当前的会话是否是由cookie模式获取的
     */
    public boolean isUuidCookieless() {
        return isUuidCookieless;
    }


    /**
     * 返回当前的会话id键值
     */
    public String getIdKey() {
        return SESSION_ID_KEY;
    }


    /**
     * 返回当前的会话id键值
     */
    public String getUuIdKey() {
        return UUID_ID_KEY;
    }
    /**
     * 返回当前的会话id
     */
    public String getId() {
        if (sessionId == null) {
            isCookieless = false;
            isNew = false;
            Http.Request request = Http.Request.current();
            if (request != null) {
                //优先从查询参数获取
                sessionId = request.params.get(SESSION_ID_KEY);
                Http.Cookie cookie = request.cookies.get(SESSION_ID_KEY);
                if(sessionId == null || !sessionParser.matcher(sessionId).find()){
                    //再从cookie里获取
                    if (cookie != null) {
                        sessionId = cookie.value;
                        isCookieless = true;
                    }
                }else if(cookie != null){
                    //判断与cookie里的sessionid值是否一样
                    if(sessionId.equals(cookie.value)){
                        isCookieless = true;
                    }
                }
            }
            if (sessionId == null || !sessionParser.matcher(sessionId).find()) {
                sessionId = Codec.hexMD5(Codec.UUID());
                isNew = true;
            }
        }
        return sessionId;
    }



    public String getUuId() {
        if (uuid == null) {
            isUuidCookieless = false;
            isUuidNew = false;
            Http.Request request = Http.Request.current();
            if (request != null) {
                //优先从查询参数获取
                uuid = request.params.get(UUID_ID_KEY);
                Http.Cookie cookie = request.cookies.get(UUID_ID_KEY);
                if(uuid == null){
                    //再从cookie里获取
                    if (cookie != null) {
                        uuid = cookie.value;
                        isUuidCookieless = true;
                    }
                }else if(cookie != null){
                    //判断与cookie里的sessionid值是否一样
                    if(uuid.equals(cookie.value)){
                        isUuidCookieless = true;
                    }
                }
            }
            if (uuid == null) {
                uuid = Codec.UUID();
                isUuidNew = true;
            }
        }
        return uuid;
    }
    /**
     * 获取数据键值
     *
     * @param key
     */
    private String getDataKey(String key) {
        if (key.equals(SESSION_ID_KEY)) {
            return SESSION_DAT_PREFIX.concat("/").concat(this.getId()).concat("/").concat(key);
        }else{
            return SESSION_DAT_PREFIX.concat("/").concat(this.getUuId()).concat("/").concat(key);
        }
    }

    /**
     * 获取某个值
     *
     * @param key
     */
    public Object get(String key) {
        String valueKey = getDataKey(key);
        Object value = Cache.get(valueKey);
        if (value != null) {
            //重新刷新时间
            Cache.safeReplace(valueKey, value, SESSION_DAT_EXPIRE);
        }
        return value;
    }

    /**
     * 获取某个值
     *
     * @param key
     */
    public <T> T get(String key, Class<T> type) {
        String valueKey = getDataKey(key);
        T value = Cache.get(valueKey, type);
        if (value != null) {
            //重新刷新时间
            Cache.safeReplace(valueKey, value, SESSION_DAT_EXPIRE);
        }
        return value;
    }

    /**
     * 移除某个值
     *
     * @param key
     */
    public boolean remove(String key) {
        return Cache.safeDelete(getDataKey(key));
    }

    /**
     * 添加某个值
     *
     * @param key
     * @param value
     */
    public void add(String key, Object value) {
        Cache.safeSet(getDataKey(key), value, SESSION_DAT_EXPIRE);
    }
}